/**
 *  Item.java : IceBird project
 *  17:12:13 
 */
package icebird.compiler.ncomp.vs;

import icebird.compiler.ncomp.X86Register;
import icebird.metadata.BasicType;

/**
 * Represents intermediate value, located on virtual(or VM)
 * stack.
 * @author Sergey Shulepoff[Knott]
 */
public abstract class Item {
	
	private boolean released = false;
	private Location loc;
	
	protected Item(Location l) {
		loc = l;
	}
	
	/**
	 * Returns type of this item.
	 * @return BasicType
	 */
	public abstract BasicType getType();
	
	/**
	 * Gets actual location of this item.
	 * @return Location
	 */
	public final Location getLocation() {
		return loc;
	}
	
	/**
	 * Sets actual location of this item.
	 * @return void
	 */
	public final void setLocation(Location loc) {
		this.loc = loc;
	}
	
	/**
	 * Gets computional category
	 * @return int
	 */
	public abstract int getCategory();
	
	/**
	 * Load this item to register(Depending to its type).
	 * @return void
	 */
	public abstract void load();
	
	/**
	 * Load this item to GP Register.
	 * @return void
	 */
	public abstract void loadGPR();
	
	/**
	 * Load this item to SSE register.
	 * @return void
	 */
	public abstract void loadSSE();
	
	/**
	 * Clone this item.
	 */
	public abstract Item clone();
	
	/**
	 * Push value to stack.
	 * @return void
	 */
	public abstract void push();
	
	/**
	 * Push to fpu.
	 * @return void
	 */
	public abstract void pushFPU();
	
	/**
	 * Is this item uses specified register?
	 * @return boolean
	 */
	public abstract boolean uses(X86Register r);
	
	protected abstract void doRelease();
	
	public final boolean isReleased() {
		return (released == true);
	}
	
	/**
	 * Release resources.
	 * @return void
	 */
	public final void release() {
		doRelease();
		
		released = true;
	}


	public final String toString() {
		StringBuffer buf = new StringBuffer();
		
		buf.append(getType());
		buf.append(":");
		buf.append(getLocation());
		
		return buf.toString();
	}
	
	/**
	 * Pure virtual item.
	 * @return boolean
	 */
	public final boolean isPureVirtual() {
		if (getLocation().isConstant()) {
			return true;
		}
		
		return false;
	}

	public static Item getByType(BasicType t, Location l) {
		if (!t.isPrimitive() && !t.isArray()) {
			return new RefItem(l);
		}
		
		if (t == BasicType.Int) {
			return new IntegerItem(l);
		} else if (t == BasicType.Float) {
			return new FloatItem(l);
		} else if (t == BasicType.Double) {
			return new DoubleItem(l);
		} else if (t == BasicType.Long) {
			return new LongItem(l);
		} else {
			throw new RuntimeException("Unknown type");
		}
	}
}
